MIIA-4203 MODELOS AVANZADOS PARA ANÁLISIS DE DATOS II

Red neuronal profunda

Profesor: Camilo Franco (c.franco31@uniandes.edu.co)

En este cuadernos estudiaremos las redes profundas. Implementaremos nuestra propia red utilizando la biblioteca (API) Keras (https://keras.io/).

Identificaremos nuestros mejores modelos según la arquitectura de red, intentando redes multi-capa densamente conectadas y haciendo uso de regularización para el cálculo de su función de pérdida.

Probaremos nuestros modelos más complejos de deep learning para la detección automática de frailejones sobre imagenes aereas del páramo e intentaremos mejorar los resultados que obtuvimos con nuestras redes más sencillas. Recordemos que hasta ahora hemos logrado unos resultados preliminares con un accuracy de validación de 0.86, utilizando una red sencilla de 5 neuronas.

In [6]:
from google.colab import drive
drive.mount('/content/drive')
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
In [7]:
!cp "drive/My Drive/ImportImagenesRGB.py" .
In [8]:
!cp "drive/My Drive/data_F" .
In [9]:
!cp "drive/My Drive/IMG_3451.JPG" .
In [10]:
!pip install livelossplot
Requirement already satisfied: livelossplot in /usr/local/lib/python3.6/dist-packages (0.5.3)
Requirement already satisfied: ipython in /usr/local/lib/python3.6/dist-packages (from livelossplot) (5.5.0)
Requirement already satisfied: matplotlib; python_version >= "3.6" in /usr/local/lib/python3.6/dist-packages (from livelossplot) (3.2.2)
Requirement already satisfied: bokeh; python_version >= "3.6" in /usr/local/lib/python3.6/dist-packages (from livelossplot) (2.1.1)
Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (50.3.0)
Requirement already satisfied: simplegeneric>0.8 in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (0.8.1)
Requirement already satisfied: pexpect; sys_platform != "win32" in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (4.8.0)
Requirement already satisfied: pygments in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (2.6.1)
Requirement already satisfied: traitlets>=4.2 in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (4.3.3)
Requirement already satisfied: pickleshare in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (0.7.5)
Requirement already satisfied: decorator in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (4.4.2)
Requirement already satisfied: prompt-toolkit<2.0.0,>=1.0.4 in /usr/local/lib/python3.6/dist-packages (from ipython->livelossplot) (1.0.18)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib; python_version >= "3.6"->livelossplot) (0.10.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib; python_version >= "3.6"->livelossplot) (1.2.0)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib; python_version >= "3.6"->livelossplot) (2.8.1)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib; python_version >= "3.6"->livelossplot) (2.4.7)
Requirement already satisfied: numpy>=1.11 in /usr/local/lib/python3.6/dist-packages (from matplotlib; python_version >= "3.6"->livelossplot) (1.18.5)
Requirement already satisfied: pillow>=4.0 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (7.0.0)
Requirement already satisfied: packaging>=16.8 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (20.4)
Requirement already satisfied: Jinja2>=2.7 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (2.11.2)
Requirement already satisfied: PyYAML>=3.10 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (3.13)
Requirement already satisfied: tornado>=5.1 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (5.1.1)
Requirement already satisfied: typing-extensions>=3.7.4 in /usr/local/lib/python3.6/dist-packages (from bokeh; python_version >= "3.6"->livelossplot) (3.7.4.3)
Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.6/dist-packages (from pexpect; sys_platform != "win32"->ipython->livelossplot) (0.6.0)
Requirement already satisfied: ipython-genutils in /usr/local/lib/python3.6/dist-packages (from traitlets>=4.2->ipython->livelossplot) (0.2.0)
Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from traitlets>=4.2->ipython->livelossplot) (1.15.0)
Requirement already satisfied: wcwidth in /usr/local/lib/python3.6/dist-packages (from prompt-toolkit<2.0.0,>=1.0.4->ipython->livelossplot) (0.2.5)
Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.6/dist-packages (from Jinja2>=2.7->bokeh; python_version >= "3.6"->livelossplot) (1.1.1)

Importemos algunos de los paquetes que vamos a utilizar:

In [11]:
import numpy as np
import h5py
import matplotlib.pyplot as plt

from ImportImagenesRGB import *
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix 

%load_ext autoreload
%autoreload 2

import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

from prettytable import PrettyTable
import datetime

import keras
import tensorflow as tf
from keras.models import Sequential, load_model
from keras.optimizers import SGD
from keras.layers import Activation, Dropout, Flatten, Dense

from keras.callbacks import EarlyStopping, ModelCheckpoint
from livelossplot import PlotLossesKeras

from numpy.random import seed
seed(1)

1. Redes , Validación cruzada doble (DVC) y GD estocástico (SGD)

A continuacion repliquemos el modelo de red sencilla con 5 neuronas que ya construimos paso a paso en clases anteriores. Pero esta vez utilizando la funcion modelde Keras, que añade capas secuencialmente.

Validación cruzada doble (DCV)

Repetimos varias veces el entrenamiento, validación y prueba de los modelos con distintas particiones de los datos, implementando una validación cruzada doble con el fin de obtener una estimación insesgada del error de predicción (para mayores detalles ver Filmozer et al (2009), http://www.libpls.net/publication/rdCV_2009.pdf) Esta implementación es útil cuando tenemos pocos datos.

Descenso en la Dirección del Gradiente Estocástico (SGD)

Para esta primera red sencilla, el proceso de optimización lo vamos a implementar de acuerdo con el método de Descenso en la Dirección del Gradiente Estocástico (SGD). Como ya hemos visto, el método de Descenso en la direccion del gradiente es un método iterativo que permite optimizar funciones objetivo diferenciables, donde

$$ \hat \theta_{nuevo} = \hat \theta_{viejo} - \alpha \frac{\partial J(\hat \theta_{viejo}; X, Y) }{ \partial \hat \theta_{viejo} }$$

siendo $\alpha$ la tasa de aprendizaje y $\theta$ nuestro parámetro a estimar.

La parte estocástica se refiere a que en lugar de utilizar todos los datos en cada paso iterativo, utilizamos una observación (elegida de manera aleatoria) en cada paso. De esta manera, el SGD permite reducir el coste computacional del proceso de optimización, iterando más rápidamente pero con un tasa de convergencia ligeramente menor y más oscilante.

Entonces, el SGD se puede formular de la siguiente manera

$$ \hat \theta_{nuevo} = \hat \theta_{viejo} - \alpha \frac{\partial J (\hat \theta_{viejo}; x^{(i)}, y^{(i)})}{ \partial \hat \theta_{viejo} }$$

Fijémnos que una variación del GD a medio-camino del SGD es el GD en batches o subconjuntos de datos con un tamaño dado (16, 32, 64,...), el cual optimiza sobre distintos subconjuntos (aleatoriamente seleccionados) del total de los datos en cada iteración.

Además se tienen otras modificaciones sobre el SGD. La más opular es la adición de un término de momentum.

SGD con momentum

Recordando las nociones de física, el término momentum hace referencia al algoritmo que avanza a lo largo del espacio paramétrico en búsqueda del óptimo (local), aceleradno de acuerdo con el gradiente de la pérdida (que guardando la anlogía con la física, se refiere a la fuerza). De esta manera, modificando el GD clásico, pues mantiene la misma dirección a medida que avanza disminuyendo las oscilaciones.

Este método hace parte de la literatura del aprendizaje computacional basado en la retro-propagación (Rumelhart et al. (1986) https://www.nature.com/articles/323533a0)

El SGD con momentum actualiza los estimadores como una combinación lineal entre el gradiente y la actualización previa, implementando un promedio suavizado:

$$ \hat \theta_{nuevo} = \eta \hat \theta_{viejo} - \alpha \frac{\partial J (\hat \theta_{viejo}; x^{(i)}, y^{(i)})}{ \partial \hat \theta_{viejo} }$$

donde $\eta$ es el factor de decrecimiento exponencial que toma valores entre 0 y 1. Así, $\eta$ permite incorporar la contribución relativa entre el gradiente actual y de gradientes anteriores.

A continuación importemos las imagenes:

In [12]:
X,Y = import_imagenes_RGB()

print(X.shape, Y.shape, X[0,0,0])
(250, 70, 70, 3) (1, 250) [0.58823529 0.5372549  0.40392157]

Salida esperada:

(250, 70, 70, 3) (1, 250) [0.58823529 0.5372549 0.40392157]

In [ ]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca"])
Acc_E = []
Acc_V = []
Acc_P = []

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=1000

# Definimos los parametros del SGD
sgd = SGD(lr=0.01, momentum=0.001)
# junto con la inicialización aleatoria
initnorm = keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=1)

# inicializamos el error para guardar el mejor modelo
err_p = 999
  
# implementamos 3 repeticiones con particiones distintas de entrenamiento y doble validacion
for i in range(0,3,1):
    r = i^3
    CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = r)
    CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = r)
       
    # Especificamos la arquitectura de la red 
    model = Sequential()  
    model.add(Flatten(input_shape=CE_x.shape[1:]))
    model.add(Dense(5, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros'))
    model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
    
    # Ajustamos el modelo
    history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False) 
    
    # Encontramos el mejor modelo en validación
    min_err=np.min(history.history['val_loss'])
    best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en validación
    model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
    train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
    valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
    test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
            
    # Guardamos las métricas de desempeño
    accu_e = train_metrics[1]
    loss_e = train_metrics[0]
    accu_v = valid_metrics[1]
    loss_v = valid_metrics[0]
    accu_p = test_metrics[1]
    loss_p = test_metrics[0]
    
    if (loss_p < err_p):
        pathr =('modelo_redsencilla_initseed=1_part_seed='+str(r)+'numn=5.h5')
        model.save(pathr) 
        err_p = loss_p
    
    # Imprimimos el desempeño para cada repetición
    print('Epoca= '+str(best_epoc[0])+' y accu_v='+str(accu_v))
    
    x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0]])
    
    # Exactitud media
    Acc_E.append(accu_e)
    Acc_V.append(accu_v)
    Acc_P.append(accu_p)

print(x)

print('Accuracies de Entrenamiento: '+str(np.round(np.mean(Acc_E),3))
      +'; Validacion1: '+str(np.round(np.mean(Acc_V),3))+ '; Validacion2: '+str(np.round(np.mean(Acc_P),3)))
Epoca= 764 y accu_v=0.7837837934494019
Epoca= 640 y accu_v=0.8648648858070374
Epoca= 412 y accu_v=0.8108108043670654
+--------+--------+--------+-------+
| Exac_E | Exac_V | Exac_P | Epoca |
+--------+--------+--------+-------+
| 0.9943 | 0.7838 | 0.8158 |  764  |
| 0.9829 | 0.8649 | 0.7895 |  640  |
| 0.9714 | 0.8108 | 0.7895 |  412  |
+--------+--------+--------+-------+
Accuracies de Entrenamiento: 0.983; Validacion1: 0.82; Validacion2: 0.798

Graficamos el desempeño del modelo:

In [ ]:
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud')  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida')  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

Confirmamos que podemos cargar de nuevo el modelo que guardamos:

In [ ]:
# red sencilla 5 neuronas
model_1 = load_model('modelo_redsencilla_initseed=1_part_seed=3numn=5.h5')

Pregunta 1.1

Cuántos parámetros debemos estimar en esta red sencilla?

In [ ]:
Input_layer  = CE_x.shape[1]
Input_bias   = 1
Hidden_layer = 5
Hidden_bias  = 1
Output_layer = 1

Total_param = (Input_layer+Input_bias)*Hidden_layer+(Hidden_layer+Hidden_bias)*Output_layer

Total_param
Out[ ]:
361

Replicabilidad

Confirmamos el desempeño del modelo sobre todo el conjunto de datos:

In [ ]:
Y_pred = model_1.predict(X)
Y_preds = (Y_pred > 0.5)

confusion_matrix(Y.T, Y_preds)
Out[ ]:
array([[140,   5],
       [ 11,  94]])

Salida esperada:

140 5
7 98

Ejercicio 1.1

Busque un mejor modelo intentando diferentes inicializaciones para la estimación de los parámetros.

In [ ]:
##### MEJORA 1 --> Inicialización He en capa oculta #######

# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca"])
Acc_E = []
Acc_V = []
Acc_P = []

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=1000

# Definimos los parametros del SGD
sgd = SGD(lr=0.01, momentum=0.001)
# junto con la inicialización aleatoria

initnorm = keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=1)
initHe = keras.initializers.he_normal(seed=1)

# inicializamos el error para guardar el mejor modelo
err_p = 999
  
# implementamos 3 repeticiones con particiones distintas de entrenamiento y doble validacion
for i in range(0,3,1):
    r = i^3
    CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = r)
    CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = r)
       
    # Especificamos la arquitectura de la red 
    model = Sequential()  
    model.add(Flatten(input_shape=CE_x.shape[1:]))
    model.add(Dense(5, activation='sigmoid', kernel_initializer=initHe, bias_initializer='zeros'))
    model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
    
    # Ajustamos el modelo
    history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False) 
    
    # Encontramos el mejor modelo en validación
    min_err=np.min(history.history['val_loss'])
    best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en validación
    model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
    train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
    valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
    test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
            
    # Guardamos las métricas de desempeño
    accu_e = train_metrics[1]
    loss_e = train_metrics[0]
    accu_v = valid_metrics[1]
    loss_v = valid_metrics[0]
    accu_p = test_metrics[1]
    loss_p = test_metrics[0]
    
    if (loss_p < err_p):
        pathr =('modelo_redsencilla_initseed=1_part_seed='+str(r)+'numn=5.h5')
        model.save(pathr) 
        err_p = loss_p
    
    # Imprimimos el desempeño para cada repetición
    print('Epoca= '+str(best_epoc[0])+' y accu_v='+str(accu_v))
    
    x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0]])
    
    # Exactitud media
    Acc_E.append(accu_e)
    Acc_V.append(accu_v)
    Acc_P.append(accu_p)

print(x)

print('Accuracies de Entrenamiento: '+str(np.round(np.mean(Acc_E),3))
      +'; Validacion1: '+str(np.round(np.mean(Acc_V),3))+ '; Validacion2: '+str(np.round(np.mean(Acc_P),3)))
Epoca= 589 y accu_v=0.7837837934494019
Epoca= 518 y accu_v=0.837837815284729
Epoca= 485 y accu_v=0.8108108043670654
+--------+--------+--------+-------+
| Exac_E | Exac_V | Exac_P | Epoca |
+--------+--------+--------+-------+
|  1.0   | 0.7838 | 0.8684 |  589  |
| 0.9943 | 0.8378 | 0.8158 |  518  |
| 0.9771 | 0.8108 | 0.8158 |  485  |
+--------+--------+--------+-------+
Accuracies de Entrenamiento: 0.99; Validacion1: 0.811; Validacion2: 0.833
In [ ]:
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud')  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida')  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

R/ Al realizar la inicialización de He se evidencia una mejora en el accuracy que para el escenario inicial no superaba el 0.8.

In [ ]:
### Momentum en 0.01 --> Resultados no cambian

### Momentum en 0.1  --> No hubo mejora en los resultados

### stddev = 0.5     --> Empeora resultados Accuracies de Entrenamiento: 0.874; Validacion1: 0.721; Validacion2: 0.754
Epoca= 999 y accu_v=0.6756756901741028
Epoca= 999 y accu_v=0.7567567825317383
Epoca= 999 y accu_v=0.7297297120094299
+--------+--------+--------+-------+
| Exac_E | Exac_V | Exac_P | Epoca |
+--------+--------+--------+-------+
| 0.9029 | 0.6757 | 0.7895 |  999  |
| 0.8514 | 0.7568 | 0.6316 |  999  |
| 0.8686 | 0.7297 | 0.8421 |  999  |
+--------+--------+--------+-------+
Accuracies de Entrenamiento: 0.874; Validacion1: 0.721; Validacion2: 0.754

2. Redes profundas

Ahora implementemos una red multi-capa, añadiendo más capas al modelo. Primero definimos la técnica de inicialización de He que vimos la clase pasada, la cual está pensada para aliviar el entenamiento de redes profundas con funciones de activación basadas en los rectficadores ReLU.

Recordemos que la inicialización de He para los parametros $W^{[l]}$ consiste en multiplicar sus valores iniciales por $\sqrt{\frac{2}{n_l}}$.

Ahora, para esta red profunda, vamos a utilizar un método de optimización que nos ayude a reducir el coste computacional que conlleva un número aumentado de parámetros a estimar.

Propagación de la raiz cuadrada del Cuadrado Medio (RMSProp)

El método de propagación de la raiz cuadrada del cuadrado medio (RMSProp Root Mean Square Propagation) permite adaptar la tasa de aprendizaje para cada uno de los parámetros. Esto se hace dividiendo la tasa de aprendizaje (para un parámetro) por un promedio móvil de las magnitudes de los gradientes recientes (ver https://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf )

De esta manera, un primer promedio movil se calcula en términos de los cuadrados medios del gradiente y el parámetro $\rho$ que representa un factor de memoria a corto plazo sobre los gradientes recientes:

$$ v(\theta) = \rho v(\theta_{viejo}) + (1-\rho) \biggr( \frac{\partial J (\hat \theta_{viejo}; x^{(i)}, y^{(i)})}{ \partial \hat \theta_{viejo} } \biggl)^2 $$

De tal manera que la actualización de los parámetros se lleva a cabo mediante:

$$ \hat \theta_{nuevo} = \hat \theta_{viejo} - \frac{\alpha}{\sqrt{v(\theta)}} \frac{\partial J (\hat \theta_{viejo}; x^{(i)}, y^{(i)})}{ \partial \hat \theta_{viejo} }$$

Esta implementación del RMSProp permite adaptar la tasa de aprendizaje sobre la optimización con todos los datos o pequeños subconjuntos de los datos.

Antes de especificar la estructura de la red, primero definamos la inicializacion de He:

In [ ]:
initHe = keras.initializers.he_normal(seed=1)

Veamos cómo podemos agregar más capas al modelo que definimos con la ayuda de Keras. A continuación definimos la arquitectura de la red, una con inicializacion aleatoria normal y otra con la incializacion de He:

In [ ]:
model = Sequential()  
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))  
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_norm = model.get_config()
In [ ]:
model = Sequential()   
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initHe, bias_initializer='zeros')) 
model.add(Dense(400, activation='relu', kernel_initializer=initHe, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initHe, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initHe, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initHe, bias_initializer='zeros'))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_He = model.get_config()

Ahora implementamos el codigo para buscar el mejor modelo con la arquitectura arriba definida, probando ambos métodos de incialización:

In [ ]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca", "Init"])

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=200

# Definimos los parametros del RMSProp
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
x
# implementamos 2 repeticiones, una con inicializacion aleatoria Normal y otra con He
for i in range(2):
    if(i==0):
        model = Sequential.from_config(config_norm)
        init = "Normal"
        tiempo0 = datetime.datetime.now()
        print('Inicio Init=' +str(init)+':' +str(tiempo0))
    elif(i==1):
        model = Sequential.from_config(config_He)
        init = "He"
        tiempo0 = datetime.datetime.now()
        print('Inicio Init=' +str(init)+':' +str(tiempo0))
        
    # Partimos los datos en entrenamiento y doble validación
    CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
    CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
    model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])
    
    # Ajustamos el modelo
    history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  
  
    # Encontramos el mejor modelo en validación
    min_err=np.min(history.history['val_loss'])
    best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en la primera validación
    model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
    train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
    valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
    test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
           
    # Guardamos las métricas de desempeño
    accu_e = train_metrics[1]
    loss_e = train_metrics[0]
    accu_v = valid_metrics[1]
    loss_v = valid_metrics[0]
    accu_p = test_metrics[1]
    loss_p = test_metrics[0]
    
    pathr =('modelo_redprofunda_initseed=1_part_seed=8_Init='+str(init)+'.h5')
    model.save(pathr) 
    err_p = loss_p
    
    x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0], init])
    
    # Imprimimos el desempeño para cada inicializacion y el tiempo en completar las iteraciones
    print('Epoca= '+str(best_epoc[0])+' , accu_v1='+str(accu_v) +' , accu_v2='+str(accu_p))
    tiempo1 = datetime.datetime.now()
    print('Fin Init= ' +str(init)+':' +str(tiempo1))
    
    # Graficamos el desempeño del modelo
    plt.figure(1)
    plt.plot(history.history['accuracy'])  
    plt.plot(history.history['val_accuracy'])  
    plt.title('Exactitud inicializacion ' +str(init))  
    plt.ylabel('Acc')  
    plt.xlabel('Epoca')  
    plt.legend(['Entreno', 'Validacion'], loc='lower right')
    plt.show()

    plt.figure(1) 
    plt.plot(history.history['loss'])  
    plt.plot(history.history['val_loss'])  
    plt.title('Pérdida inicializacion ' +str(init))  
    plt.ylabel('Pérdida')  
    plt.xlabel('Epoca')  
    plt.legend(['Entreno', 'Validación'], loc='upper right')  
    plt.show()

print(x)
Inicio Init=Normal:2020-09-19 18:01:39.333489
Epoca= 186 , accu_v1=0.8648648858070374 , accu_v2=0.8421052694320679
Fin Init= Normal:2020-09-19 18:05:38.426613
Inicio Init=He:2020-09-19 18:05:39.046413
Epoca= 177 , accu_v1=0.8648648858070374 , accu_v2=0.7894737124443054
Fin Init= He:2020-09-19 18:09:35.185981
+--------+--------+--------+-------+--------+
| Exac_E | Exac_V | Exac_P | Epoca |  Init  |
+--------+--------+--------+-------+--------+
|  1.0   | 0.8649 | 0.8421 |  186  | Normal |
| 0.9829 | 0.8649 | 0.7895 |  177  |   He   |
+--------+--------+--------+-------+--------+

Pregunta 2.1

Qué método de inicialización ayuda más a la convergencia del modelo?

R/ A medida que van transcurriendo las épocas la inicialización Normal muestra una mayor estabilidad en los valores de accuracy y de pérdida, mientras que con la inicialización de He se observa mayor varianza.

Cargamos el mejor modelo y confirmamos el desempeño del modelo sobre todo el conjunto de datos:

In [ ]:
# red profunda de 6 capas
model_2 = load_model('modelo_redprofunda_initseed=1_part_seed=8_Init=Normal.h5')

model_2.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten_3 (Flatten)          (None, 14700)             0         
_________________________________________________________________
dense_6 (Dense)              (None, 700)               10290700  
_________________________________________________________________
dense_7 (Dense)              (None, 400)               280400    
_________________________________________________________________
dense_8 (Dense)              (None, 100)               40100     
_________________________________________________________________
dense_9 (Dense)              (None, 50)                5050      
_________________________________________________________________
dense_10 (Dense)             (None, 15)                765       
_________________________________________________________________
dense_11 (Dense)             (None, 1)                 16        
=================================================================
Total params: 10,617,031
Trainable params: 10,617,031
Non-trainable params: 0
_________________________________________________________________
In [ ]:
Y_pred = model_2.predict(X)
Y_preds = (Y_pred > 0.5)

confusion_matrix(Y.T, Y_preds)
Out[ ]:
array([[139,   6],
       [  4, 101]])

Salida esperada (aproximada):

139 6
6 99

Ejercicio 2.1

Explore la implementación de regularizacion L1 y L2 sobre la última capa escondida para mejorar el desempeño en validación de la red.

*Ayuda: visite la pagina de Keras https://keras.io/regularizers/ para aplicar regularización sobre la magnitud de los parametros, implemente kernel_regularizer Por ejemplo, si queremos una regularización L2 con una constante de 0.01, escribimos kernel_regularizer=regularizers.l2(0.01)

In [13]:
from tensorflow.keras import regularizers
In [ ]:
# Regularización L1

model = Sequential()  
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))  
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros', kernel_regularizer=regularizers.l1(0.01)))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_norm = model.get_config()
In [ ]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca", "Init"])

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=200

# Definimos los parametros del RMSProp
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
x
# implementamos 2 repeticiones, una con inicializacion aleatoria Normal y otra con He
#for i in range(2):
#    if(i==0):
model = Sequential.from_config(config_norm)
init = "Normal"
tiempo0 = datetime.datetime.now()
print('Inicio Init=' +str(init)+':' +str(tiempo0))
#    elif(i==1):
#        model = Sequential.from_config(config_He)
#        init = "He"
#        tiempo0 = datetime.datetime.now()
#        print('Inicio Init=' +str(init)+':' +str(tiempo0))
        
    # Partimos los datos en entrenamiento y doble validación
CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])
    
    # Ajustamos el modelo
history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  
  
    # Encontramos el mejor modelo en validación
min_err=np.min(history.history['val_loss'])
best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en la primera validación
model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
           
    # Guardamos las métricas de desempeño
accu_e = train_metrics[1]
loss_e = train_metrics[0]
accu_v = valid_metrics[1]
loss_v = valid_metrics[0]
accu_p = test_metrics[1]
loss_p = test_metrics[0]
    
pathr =('modelo_redprofunda_initseed=1_part_seed=8_Init='+str(init)+'.h5')
model.save(pathr) 
err_p = loss_p
    
x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0], init])
    
    # Imprimimos el desempeño para cada inicializacion y el tiempo en completar las iteraciones
print('Epoca= '+str(best_epoc[0])+' , accu_v1='+str(accu_v) +' , accu_v2='+str(accu_p))
tiempo1 = datetime.datetime.now()
print('Fin Init= ' +str(init)+':' +str(tiempo1))
    
    # Graficamos el desempeño del modelo
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud inicializacion ' +str(init))  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida inicializacion ' +str(init))  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

print(x)
Inicio Init=Normal:2020-09-18 21:05:53.226263
Epoca= 190 , accu_v1=0.8918918967247009 , accu_v2=0.8421052694320679
Fin Init= Normal:2020-09-18 21:06:19.146049
+--------+--------+--------+-------+--------+
| Exac_E | Exac_V | Exac_P | Epoca |  Init  |
+--------+--------+--------+-------+--------+
|  1.0   | 0.8919 | 0.8421 |  190  | Normal |
+--------+--------+--------+-------+--------+
In [ ]:
# Regularización L2

model = Sequential()  
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))  
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros', kernel_regularizer=regularizers.l2(0.01)))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_norm = model.get_config()
In [ ]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca", "Init"])

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=200

# Definimos los parametros del RMSProp
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
x
# implementamos 2 repeticiones, una con inicializacion aleatoria Normal y otra con He
#for i in range(2):
#    if(i==0):
model = Sequential.from_config(config_norm)
init = "Normal"
tiempo0 = datetime.datetime.now()
print('Inicio Init=' +str(init)+':' +str(tiempo0))
#    elif(i==1):
#        model = Sequential.from_config(config_He)
#        init = "He"
#        tiempo0 = datetime.datetime.now()
#        print('Inicio Init=' +str(init)+':' +str(tiempo0))
        
    # Partimos los datos en entrenamiento y doble validación
CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])
    
    # Ajustamos el modelo
history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  
  
    # Encontramos el mejor modelo en validación
min_err=np.min(history.history['val_loss'])
best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en la primera validación
model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
           
    # Guardamos las métricas de desempeño
accu_e = train_metrics[1]
loss_e = train_metrics[0]
accu_v = valid_metrics[1]
loss_v = valid_metrics[0]
accu_p = test_metrics[1]
loss_p = test_metrics[0]
    
pathr =('modelo_redprofunda_initseed=1_part_seed=8_Init='+str(init)+'.h5')
model.save(pathr) 
err_p = loss_p
    
x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0], init])
    
    # Imprimimos el desempeño para cada inicializacion y el tiempo en completar las iteraciones
print('Epoca= '+str(best_epoc[0])+' , accu_v1='+str(accu_v) +' , accu_v2='+str(accu_p))
tiempo1 = datetime.datetime.now()
print('Fin Init= ' +str(init)+':' +str(tiempo1))
    
    # Graficamos el desempeño del modelo
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud inicializacion ' +str(init))  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida inicializacion ' +str(init))  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

print(x)
Inicio Init=Normal:2020-09-18 21:07:35.769112
Epoca= 187 , accu_v1=0.8918918967247009 , accu_v2=0.8421052694320679
Fin Init= Normal:2020-09-18 21:08:01.589737
+--------+--------+--------+-------+--------+
| Exac_E | Exac_V | Exac_P | Epoca |  Init  |
+--------+--------+--------+-------+--------+
|  1.0   | 0.8919 | 0.8421 |  187  | Normal |
+--------+--------+--------+-------+--------+
In [ ]:
# Regularización L1_L2

model = Sequential()  
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))  
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros', kernel_regularizer=regularizers.l1_l2(l1=0.01,l2=0.01)))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_norm = model.get_config()
In [ ]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca", "Init"])

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=200

# Definimos los parametros del RMSProp
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
x
# implementamos 2 repeticiones, una con inicializacion aleatoria Normal y otra con He
#for i in range(2):
#    if(i==0):
model = Sequential.from_config(config_norm)
init = "Normal"
tiempo0 = datetime.datetime.now()
print('Inicio Init=' +str(init)+':' +str(tiempo0))
#    elif(i==1):
#        model = Sequential.from_config(config_He)
#        init = "He"
#        tiempo0 = datetime.datetime.now()
#        print('Inicio Init=' +str(init)+':' +str(tiempo0))
        
    # Partimos los datos en entrenamiento y doble validación
CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])
    
    # Ajustamos el modelo
history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  
  
    # Encontramos el mejor modelo en validación
min_err=np.min(history.history['val_loss'])
best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en la primera validación
model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
           
    # Guardamos las métricas de desempeño
accu_e = train_metrics[1]
loss_e = train_metrics[0]
accu_v = valid_metrics[1]
loss_v = valid_metrics[0]
accu_p = test_metrics[1]
loss_p = test_metrics[0]
    
pathr =('modelo_redprofunda_initseed=1_part_seed=8_Init='+str(init)+'.h5')
model.save(pathr) 
err_p = loss_p
    
x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0], init])
    
    # Imprimimos el desempeño para cada inicializacion y el tiempo en completar las iteraciones
print('Epoca= '+str(best_epoc[0])+' , accu_v1='+str(accu_v) +' , accu_v2='+str(accu_p))
tiempo1 = datetime.datetime.now()
print('Fin Init= ' +str(init)+':' +str(tiempo1))
    
    # Graficamos el desempeño del modelo
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud inicializacion ' +str(init))  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida inicializacion ' +str(init))  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

print(x)
Inicio Init=Normal:2020-09-18 21:03:57.592795
Epoca= 183 , accu_v1=0.8918918967247009 , accu_v2=0.8421052694320679
Fin Init= Normal:2020-09-18 21:04:23.543314
+--------+--------+--------+-------+--------+
| Exac_E | Exac_V | Exac_P | Epoca |  Init  |
+--------+--------+--------+-------+--------+
|  1.0   | 0.8919 | 0.8421 |  183  | Normal |
+--------+--------+--------+-------+--------+

Ejercicio 2.2

Revise los métodos de inicialización, el procedimiento de optimización, la arquitectura de la red y/o las funciones de activación, e intente mejorar los resultados que acabamos de obtener.

In [ ]:
# Dividiendo los datos
CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
In [ ]:
# Limpiando
keras.backend.clear_session()

# Número de epocas
epocas=200

# Nombre del modelo
modelo = "Exec="+"".join(datetime.datetime.now().strftime('%f'))

# Optimizadores
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
sgd = SGD(lr=0.01, momentum=0.001)

# Tipo de inicialización
initnorm = keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=1)
initHe = keras.initializers.he_normal(seed=1)

# Arquitectura
model = Sequential()   
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros')) 
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros', kernel_regularizer=regularizers.l1_l2(l1=0.01,l2=0.01)))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 

# Modelo
#model = Sequential.from_config(config_He)


# Compilando modelo
model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])

# Arquitectura del modelo
model.summary()


# Entrenando modelo
#model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  

# Callbacks
fBestModel = 'best_model.h5'
early_stop = EarlyStopping(monitor='accuracy', patience=20, verbose=1) 
best_model = ModelCheckpoint(fBestModel, verbose=1, save_best_only=True)
tb_callback = tf.keras.callbacks.TensorBoard(log_dir = "".join(["logs/", modelo]), histogram_freq = 1)

# Corriendo modelo con el mejor ajuste en entrenamiento
model.fit(CE_x, CE_y,         
          validation_data=(CV_x, CV_y),
          epochs=epocas,
          #batch_size=528,
          verbose = 1,
          #validation_split=0.3,
          shuffle = False,
          callbacks=[tb_callback, early_stop, best_model, PlotLossesKeras()])


# Calculamos las metricas
train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
       
# Guardamos las métricas de desempeño
accu_e = train_metrics[1]
loss_e = train_metrics[0]
accu_v = valid_metrics[1]
loss_v = valid_metrics[0]
accu_p = test_metrics[1]
loss_p = test_metrics[0]

# Guardamos el modelo
pathr =('modelo_='+modelo+'.h5')
model.save(pathr) 

# Valores de exactitud
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca"])
x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0]])
print(x)


Y_pred = model.predict(X)
Y_preds = (Y_pred > 0.5)

confusion_matrix(Y.T, Y_preds)
accuracy
	training         	 (min:    0.520, max:    0.983, cur:    0.931)
	validation       	 (min:    0.541, max:    0.892, cur:    0.865)
Loss
	training         	 (min:    0.175, max:    1.025, cur:    0.237)
	validation       	 (min:    0.357, max:    1.016, cur:    0.369)
6/6 [==============================] - 2s 299ms/step - loss: 0.2366 - accuracy: 0.9314 - val_loss: 0.3691 - val_accuracy: 0.8649
+--------+--------+--------+-------+
| Exac_E | Exac_V | Exac_P | Epoca |
+--------+--------+--------+-------+
| 0.9657 | 0.8649 | 0.8158 |  177  |
+--------+--------+--------+-------+
Out[ ]:
array([[132,  13],
       [  5, 100]])

Después de ver los resultados. Se evidencia que la exactitud del modelo en el conjunto de validación y/o en el conjunto de prueba, no mejoran mucho. Se implementa una grilla con Tensorboard y Hparams para ver la evolución con multiples corridas de cada uno de los parametros.

Vamos a modificar los siguientes hiperparámetros:

  • Arquitectura: Se modificarán el número de unidades/neuronas de las capas densas. Especificamente, la 5ta entre 100 unidaes y 300 unidades. Y la 4ta entre 16 unidades y 32 unidades.
  • Dropout: Se implementa un dropout. Entre un intervalo de 0.1 a 0.2
  • Optimizadores: Se generarán con 3 optimizadores (adam, sgd y rmsprop)
  • Inicialización: Se modificarán los inicializadores entre una inicialización con distribución normal y una inicialización de He con distribución normal.
  • Regularizaciones: Se implementa una regularización L2.

Se usará la API de hparams que tiene tensorboard. Así mismo, como se mencionó antes, se mostrará en un Tensorboard los parametros indicados enteriormente para evaluar uno a uno y tomar decisiones sobre la mejor arquitectura, optimizador e inicialización.

Puede observar el dashboard de Tensorboard.

In [ ]:
!rm -rf ./logs/ 
In [ ]:
from tensorboard.plugins.hparams import api as hp

# Optimizadores
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
sgd = SGD(lr=0.01, momentum=0.001)

# Tipo de inicialización
initnorm = keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=1)
initHe = keras.initializers.he_normal(seed=1)

# Nombre del modelo
modelo = "Exec="+"".join(datetime.datetime.now().strftime('%f'))

# Dicccionario de hiperparametros
HP_NUM_UNITS_TWO = hp.HParam('num_units_two', hp.Discrete([100, 300]))
HP_NUM_UNITS = hp.HParam('num_units', hp.Discrete([16, 32]))
HP_DROPOUT = hp.HParam('dropout', hp.RealInterval(0.1, 0.2))
HP_OPTIMIZER = hp.HParam('optimizer', hp.Discrete(['adam', 'sgd', 'rmsprop']))
HP_INIT = hp.HParam('init', hp.Discrete(['RandomNormal', 'he_normal']))
#HP_L2 = hp.HParam('l2 regularizer', hp.RealInterval(.001,.01))
METRIC_ACCURACY = 'accuracy'

# Creando directorio de hiperparametros
with tf.summary.create_file_writer('logs/hparam_tuning').as_default():
  hp.hparams_config(
    hparams=[HP_NUM_UNITS, HP_NUM_UNITS_TWO, HP_DROPOUT, HP_OPTIMIZER, HP_INIT],
    metrics=[hp.Metric(METRIC_ACCURACY, display_name='Accuracy')],
  )

def train_test_model(run_dir, hparams):
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=X.shape[1:]),
    tf.keras.layers.Dense(700, activation='relu', kernel_initializer=hparams[HP_INIT], bias_initializer='zeros'),
    tf.keras.layers.Dense(400, activation='relu', kernel_initializer=hparams[HP_INIT], bias_initializer='zeros'),
    tf.keras.layers.Dense(hparams[HP_NUM_UNITS_TWO], activation='relu', kernel_initializer=hparams[HP_INIT], bias_initializer='zeros'),
    tf.keras.layers.Dropout(hparams[HP_DROPOUT]),
    tf.keras.layers.Dense(50, activation='relu', kernel_initializer=hparams[HP_INIT], bias_initializer='zeros'),
    tf.keras.layers.Dense(hparams[HP_NUM_UNITS], activation='relu', kernel_initializer=hparams[HP_INIT], bias_initializer='zeros', kernel_regularizer=regularizers.l1_l2(l1=0.01,l2=0.01)),
    tf.keras.layers.Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')
  ])
  
  # Callbacks
  fBestModel = 'best_model.h5'
  early_stop = EarlyStopping(monitor='accuracy', patience=20, verbose=1) 
  best_model = ModelCheckpoint(fBestModel, verbose=1, save_best_only=True)

  model.compile(loss='binary_crossentropy', optimizer=hparams[HP_OPTIMIZER], metrics=['accuracy'])
  
  model.fit(CE_x, CE_y, validation_data=(CV_x, CV_y), epochs=100, callbacks=[tf.keras.callbacks.TensorBoard(run_dir), hp.KerasCallback(run_dir, hparams), PlotLossesKeras(), best_model]) #early_stop
  _, accuracy = model.evaluate(CV_x, CV_y)

  # Calculamos las metricas
  train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
  valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
  test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)

  # Guardamos las métricas de desempeño
  accu_e = train_metrics[1]
  loss_e = train_metrics[0]
  accu_v = valid_metrics[1]
  loss_v = valid_metrics[0]
  accu_p = test_metrics[1]
  loss_p = test_metrics[0]

  # Guardamos el modelo
  pathr =('modelo_'+modelo+'.h5')
  model.save(pathr) 

  # Valores de exactitud
  x = PrettyTable(["Exac_E", "Exac_V", "Exac_P"])
  x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4)])
  print("\n", x)


  Y_pred = model.predict(X)
  Y_preds = (Y_pred > 0.5)

  confusion_matrix(Y.T, Y_preds)

  return accuracy

def run(run_dir, hparams):
  with tf.summary.create_file_writer(run_dir).as_default():
    hp.hparams(hparams)
    accuracy = train_test_model(run_dir, hparams)
    tf.summary.scalar(METRIC_ACCURACY, accuracy, step=1)
In [ ]:
session_num = 0

for num_units in HP_NUM_UNITS.domain.values:
  for num_units_two in HP_NUM_UNITS_TWO.domain.values:
    for dropout_rate in (HP_DROPOUT.domain.min_value, HP_DROPOUT.domain.max_value):
      for optimizer in HP_OPTIMIZER.domain.values:
        for init in HP_INIT.domain.values:
          hparams = {
              HP_NUM_UNITS: num_units,
              HP_NUM_UNITS_TWO: num_units_two,
              HP_DROPOUT: dropout_rate,
              HP_OPTIMIZER: optimizer,
              HP_INIT: init,
          }
          run_name = "run-%d" % session_num
          print('--- Starting trial: %s' % run_name)
          print({h.name: hparams[h] for h in hparams})
          run('logs/hparam_tuning/' + run_name, hparams)
          session_num += 1
accuracy
	training         	 (min:    0.537, max:    0.863, cur:    0.857)
	validation       	 (min:    0.541, max:    0.865, cur:    0.865)
Loss
	training         	 (min:    0.433, max:    1.014, cur:    0.433)
	validation       	 (min:    0.414, max:    1.078, cur:    0.414)

Epoch 00018: val_loss improved from 0.43833 to 0.41360, saving model to best_model.h5
6/6 [==============================] - 1s 114ms/step - loss: 0.4329 - accuracy: 0.8571 - val_loss: 0.4136 - val_accuracy: 0.8649
Epoch 19/100
1/6 [====>.........................] - ETA: 0s - loss: 0.4022 - accuracy: 0.8750
In [1]:
!tensorboard dev upload --logdir ./logs/hparam_tuning \
  --name "Semana 5: Redes Profundas con Keras" \
  --description "Resultados de entrenamiento desde https://sergiomora03.github.io/deep-learning-intermediate/" \
  --one_shot
2020-09-20 22:23:49.910974: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
Data for the "graphs" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "histograms" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "hparams" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Upload started and will continue reading any new data as it's added
to the logdir. To stop uploading, press Ctrl-C.

View your TensorBoard live at: https://tensorboard.dev/experiment/mQfPPEzARJeQwocxAA8gRQ/

[2020-09-20T22:23:54] Uploader started.
yes
[2020-09-20T22:25:01] Total uploaded: 19252 scalars, 145 tensors (870 B), 48 binary objects (10.7 MB)
Listening for new data in logdir...
Done. View your TensorBoard at https://tensorboard.dev/experiment/mQfPPEzARJeQwocxAA8gRQ/
In [4]:
!tensorboard dev list
2020-09-20 22:28:00.558784: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
Data for the "graphs" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "histograms" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "hparams" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
https://tensorboard.dev/experiment/mQfPPEzARJeQwocxAA8gRQ/
	Name                 Semana 5: Redes Profundas con Keras
	Description          Resultados de entrenamiento desde https://sergiomora03.github.io/deep-learning-intermediate/
	Id                   mQfPPEzARJeQwocxAA8gRQ
	Created              2020-09-20 22:23:54 (4 minutes ago)
	Updated              2020-09-20 22:25:01 (3 minutes ago)
	Runs                 145
	Tags                 7
	Scalars              19248
	Tensor bytes         12470
	Binary object bytes  11207445
https://tensorboard.dev/experiment/nAjDT33WRxCLXNQkrD9LSQ/
	Name                 Semana 5: Redes Profundas con Keras
	Description          Resultados de entrenamiento desde https://sergiomora03.github.io/deep-learning-intermediate/
	Id                   nAjDT33WRxCLXNQkrD9LSQ
	Created              2020-09-20 16:36:49 (5 hours ago)
	Updated              2020-09-20 16:36:49 (5 hours ago)
	Runs                 0
	Tags                 0
	Scalars              0
	Tensor bytes         0
	Binary object bytes  0
Total: 2 experiment(s)
In [ ]:
!tensorboard dev delete --experiment_id m6R2aen9QWq9OgRGKZW96w
2020-09-20 16:36:28.532372: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
Data for the "graphs" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "histograms" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Data for the "hparams" plugin is now uploaded to TensorBoard.dev! Note that uploaded data is public. If you do not want to upload data for this plugin, use the "--plugins" command line argument.
Deleted experiment m6R2aen9QWq9OgRGKZW96w.
In [ ]:
%load_ext tensorboard
%tensorboard --logdir logs/
The tensorboard extension is already loaded. To reload it, use:
  %reload_ext tensorboard
Reusing TensorBoard on port 6006 (pid 124), started 0:59:05 ago. (Use '!kill 124' to kill it.)
In [2]:
%%bash
wget -q 'https://storage.googleapis.com/download.tensorflow.org/tensorboard/hparam_tuning_logs.zip'
unzip -q hparam_tuning_logs.zip -d logs/hparam_tuning
unzip:  cannot find or open hparam_tuning_logs.zip, hparam_tuning_logs.zip.zip or hparam_tuning_logs.zip.ZIP.
In [3]:
%tensorboard --logdir logs/hparam_tuning
UsageError: Line magic function `%tensorboard` not found.

Probando con regularizaciones

In [15]:
# Optimizadores
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
sgd = SGD(lr=0.01, momentum=0.001)

# Tipo de inicialización
initnorm = keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=1)
initHe = keras.initializers.he_normal(seed=1)
In [21]:
# Regularización L2

model = Sequential()  
model.add(Flatten(input_shape=X.shape[1:]))
model.add(Dense(700, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))  
model.add(Dense(400, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(100, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(50, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros'))
model.add(Dense(15, activation='relu', kernel_initializer=initnorm, bias_initializer='zeros', kernel_regularizer=regularizers.l2(0.01)))
model.add(Dense(1, activation='sigmoid', kernel_initializer=initnorm, bias_initializer='zeros')) 
    
# Guardamos la arquitectura de red
config_norm = model.get_config()
In [26]:
# Inicializamos la tabla donde guardamos los resultados
x = PrettyTable(["Exac_E", "Exac_V", "Exac_P", "Epoca", "Init"])

# Definimos el número máximo de iteraciones (épocas de la red)
epocas=200

# Definimos los parametros del RMSProp
rmsprop = keras.optimizers.RMSprop(lr=0.00008, rho=0.9)
x
# implementamos 2 repeticiones, una con inicializacion aleatoria Normal y otra con He
#for i in range(2):
#    if(i==0):
model = Sequential.from_config(config_norm)
init = "Normal"
tiempo0 = datetime.datetime.now()
print('Inicio Init=' +str(init)+':' +str(tiempo0))
#    elif(i==1):
#        model = Sequential.from_config(config_He)
#        init = "He"
#        tiempo0 = datetime.datetime.now()
#        print('Inicio Init=' +str(init)+':' +str(tiempo0))
        
    # Partimos los datos en entrenamiento y doble validación
CE_x, CV0_x, CE_y, CV0_y = train_test_split(X, Y.T, test_size = 0.3, random_state = 8)
CV_x, CP_x, CV_y, CP_y = train_test_split(CV0_x, CV0_y, test_size = 0.5, random_state = 8)
    
    # Definimos el método de optimización con respecto a su funcion de perdida (además guardamos la exactitud para cada iteracion)
model.compile(loss='binary_crossentropy', optimizer=rmsprop, metrics=['accuracy'])
    
    # Ajustamos el modelo
history=model.fit(x=CE_x, y=CE_y, epochs=epocas, validation_data=(CV_x, CV_y), verbose=0, shuffle=False)  
  
    # Encontramos el mejor modelo en validación
min_err=np.min(history.history['val_loss'])
best_epoc=np.where(history.history['val_loss'] == min_err)[0] 
        
    # Conseguimos el mejor modelo de acuerdo con su desempeño en la primera validación
model.fit(x=CE_x, y=CE_y, epochs=best_epoc[0], validation_data=(CV_x, CV_y), verbose=0, shuffle=False)
            
    # Calculamos las metricas
train_metrics = model.evaluate(x=CE_x, y=CE_y, verbose=0)
valid_metrics = model.evaluate(x=CV_x, y=CV_y, verbose=0)
test_metrics = model.evaluate(x=CP_x, y=CP_y, verbose=0)
           
    # Guardamos las métricas de desempeño
accu_e = train_metrics[1]
loss_e = train_metrics[0]
accu_v = valid_metrics[1]
loss_v = valid_metrics[0]
accu_p = test_metrics[1]
loss_p = test_metrics[0]
    
pathr =('modelo__redprofunda_initseed=1_part_seed=8_Init='+str(init)+'.h5')
model.save(pathr) 
err_p = loss_p
    
x.add_row([np.round(accu_e,4), np.round(accu_v,4), np.round(accu_p,4), best_epoc[0], init])
    
    # Imprimimos el desempeño para cada inicializacion y el tiempo en completar las iteraciones
print('Epoca= '+str(best_epoc[0])+' , accu_v1='+str(accu_v) +' , accu_v2='+str(accu_p))
tiempo1 = datetime.datetime.now()
print('Fin Init= ' +str(init)+':' +str(tiempo1))
    
    # Graficamos el desempeño del modelo
plt.figure(1)
plt.plot(history.history['accuracy'])  
plt.plot(history.history['val_accuracy'])  
plt.title('Exactitud inicializacion ' +str(init))  
plt.ylabel('Acc')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validacion'], loc='lower right')
plt.show()

plt.figure(1) 
plt.plot(history.history['loss'])  
plt.plot(history.history['val_loss'])  
plt.title('Pérdida inicializacion ' +str(init))  
plt.ylabel('Pérdida')  
plt.xlabel('Epoca')  
plt.legend(['Entreno', 'Validación'], loc='upper right')  
plt.show()

print(x)
Inicio Init=Normal:2020-09-20 22:56:11.185279
Epoca= 197 , accu_v1=0.8918918967247009 , accu_v2=0.8421052694320679
Fin Init= Normal:2020-09-20 22:56:32.747847
+--------+--------+--------+-------+--------+
| Exac_E | Exac_V | Exac_P | Epoca |  Init  |
+--------+--------+--------+-------+--------+
|  1.0   | 0.8919 | 0.8421 |  197  | Normal |
+--------+--------+--------+-------+--------+

Lectura avanzada sobre métodos de optimización en redes profundas: https://openreview.net/pdf?id=ryQu7f-RZ http://www.cs.utoronto.ca/~ilya/pubs/2013/1051_2.pdf

3. Caso aplicado

Ahora probemos nuestro modelo sobre la imagen completa de prueba del paramo IMG_3451.JPG.

In [23]:
from keras.preprocessing import image

img = image.load_img('IMG_3451.JPG')
img
Out[23]:

3.1 Red sencilla

In [ ]:
# Lo pasamos por nuestra imagen de prueba
x = np.array(img)
x2 = x

ni = x.shape[0]-50
mi = x.shape[1]-50

f1=0
f2=70
for i in range(1,ni,50):
    c1=0
    c2=70
    for j in range(1,mi,50):
        subi=x[f1:f2,c1:c2,]/255.
        subi2=np.expand_dims(subi,0)
        Y_preds = model_1.predict(subi2)
        pred_P = (Y_preds > 0.5)
        if(pred_P==1):
            x2[f1:f2,c1:c2,2]=0
        c1=c1+50
        c2=c2+50
    f1=f1+50
    f2=f2+50
        
plt.figure(figsize = (20,20))
plt.imshow(x2)
Out[ ]:
<matplotlib.image.AxesImage at 0x7f0751ce7320>

3.2 Red multi-capa

In [ ]:
# Lo pasamos por nuestra imagen de prueba
x = np.array(img)
x2 = x

ni = x.shape[0]-50
mi = x.shape[1]-50

f1=0
f2=70
for i in range(1,ni,50):
    c1=0
    c2=70
    for j in range(1,mi,50):
        subi=x[f1:f2,c1:c2,]/255.
        subi2=np.expand_dims(subi,0)
        Y_preds = model_2.predict(subi2)
        pred_P = (Y_preds > 0.5)
        if(pred_P==1):
            x2[f1:f2,c1:c2,2]=0
        c1=c1+50
        c2=c2+50
    f1=f1+50
    f2=f2+50
        
plt.figure(figsize = (20,20))
plt.imshow(x2)
Out[ ]:
<matplotlib.image.AxesImage at 0x7f0751953ef0>

Pregunta

Qué puede observar sobre el desempeño de los diferentes modelos? Qué estrategias puede proponer para mejorar los modelos?

In [ ]:
# cargaremos el modelo de mejor ajuste después de usar Tensorboard para econtrar el de mejor ajuste
model_3 = load_model('modelo_Exec=651136.h5')
In [ ]:
# Lo pasamos por nuestra imagen de prueba
x = np.array(img)
x2 = x

ni = x.shape[0]-50
mi = x.shape[1]-50

f1=0
f2=70
for i in range(1,ni,50):
    c1=0
    c2=70
    for j in range(1,mi,50):
        subi=x[f1:f2,c1:c2,]/255.
        subi2=np.expand_dims(subi,0)
        Y_preds = model_3.predict(subi2)
        pred_P = (Y_preds > 0.5)
        if(pred_P==1):
            x2[f1:f2,c1:c2,2]=0
        c1=c1+50
        c2=c2+50
    f1=f1+50
    f2=f2+50
        
plt.figure(figsize = (20,20))
plt.imshow(x2)
Out[ ]:
<matplotlib.image.AxesImage at 0x7f517aad8b70>

Tenemos claramente un sobreajuste. Los resultados de entrenamiento los puede ver en Tensorboard

Link: https://tensorboard.dev/experiment/mQfPPEzARJeQwocxAA8gRQ/#hparams

In [27]:
# cargaremos el modelo de mejor ajuste después de usar Tensorboard para econtrar el de mejor ajuste
model_4 = load_model('modelo__redprofunda_initseed=1_part_seed=8_Init=Normal.h5')
In [28]:
# Lo pasamos por nuestra imagen de prueba
x = np.array(img)
x2 = x

ni = x.shape[0]-50
mi = x.shape[1]-50

f1=0
f2=70
for i in range(1,ni,50):
    c1=0
    c2=70
    for j in range(1,mi,50):
        subi=x[f1:f2,c1:c2,]/255.
        subi2=np.expand_dims(subi,0)
        Y_preds = model_4.predict(subi2)
        pred_P = (Y_preds > 0.5)
        if(pred_P==1):
            x2[f1:f2,c1:c2,2]=0
        c1=c1+50
        c2=c2+50
    f1=f1+50
    f2=f2+50
        
plt.figure(figsize = (20,20))
plt.imshow(x2)
Out[28]:
<matplotlib.image.AxesImage at 0x7f37f63b2d30>
In [29]:
# cargaremos el modelo de mejor ajuste después de usar Tensorboard para econtrar el de mejor ajuste
model_5 = load_model('best_model.h5')
In [30]:
# Lo pasamos por nuestra imagen de prueba
x = np.array(img)
x2 = x

ni = x.shape[0]-50
mi = x.shape[1]-50

f1=0
f2=70
for i in range(1,ni,50):
    c1=0
    c2=70
    for j in range(1,mi,50):
        subi=x[f1:f2,c1:c2,]/255.
        subi2=np.expand_dims(subi,0)
        Y_preds = model_5.predict(subi2)
        pred_P = (Y_preds > 0.5)
        if(pred_P==1):
            x2[f1:f2,c1:c2,2]=0
        c1=c1+50
        c2=c2+50
    f1=f1+50
    f2=f2+50
        
plt.figure(figsize = (20,20))
plt.imshow(x2)
Out[30]:
<matplotlib.image.AxesImage at 0x7f37f6401208>
  1. Podemos observar de los diferentes modelos que el modelo 2do, tiene un mejor ajuste que el 1ro y el 3ro. Dado que tiene mejor desempeño que el primero, debido a que detecta algunos frilejones que el 1er modelo no detecto. En contraste, es mejor que el 3ro, debido a que este ya tiene un sobreajuste, debido a que clasifica más frilejones de los que realmente hay.

  2. También tenemos que resaltar que los modelos realizados con la penalización tanto L1 como L2 y su combinación (L1 y L2) muestran un mejor desempeño que un modelo sin esta pensalización.

  3. Se aprecia que a pesar de que el modelo 4. Realizado con una regulación L2 = 0.01 tiene un exactitud en validación del 0.89 No obstante, aún existen muchos frilejones que no se han clasificado correctamente.

  4. Para mejorar, realmente parece no existir con precisión un método. Pero podemos buscar nuevos valores para los hiperparametros o podríamos también cambiar radicalmente la arquitectura.

In [ ]: